////////////////////////////////////////////////////////////////////////////////////////
//
// JSimpleSim - A machine language simulator based on SimpSim by Anne-Gert Bultena.
//
// Copyright (C) 2008 Gerardo Camorlinga, Ryan Fitzgerald, and RJ Gordon
//
// This file is part of JSimpleSim.
//
// JSimpleSim is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// JSimpleSim is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with JSimpleSim.  If not, see <http://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////////////////////////////

package jsimplesim.assembler;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.LinkedHashSet;
import java.util.Scanner;

import org.apache.log4j.*;

/**
 * The main 2-Pass Assembler class. This does the job of calling the passOne()
 * and passTwo() methods. Basically, in the first pass we pull all the symbols
 * ( or labels ), and assign them to a memory location in the symbol table.
 * We also catch any syntax errors that can appear. In the second pass, we start
 * substituting in the memory locations for the symbols, and also the byte code
 * for the assembler instructions.
 * 
 * @author f08maroon
 */
public class Assembler {

    // Initialize our global vars
    static Logger logger = Logger.getLogger(Assembler.class);
    private Hashtable<String, Integer> symbolTable;
    private LinkedHashSet<String> literalTable;
    private Hashtable<String, Integer> opcodeTable;
    private ArrayList<String> Errors;
    private String code;
    private Scanner scan;
    private Scanner sym;
    private byte[] instructions;
    private int location_counter;
    private boolean error;
    private boolean opLabel;
    private boolean foundSymbol;
    private int lineNumber;
    public String hexRegEx = "^0x?[A-Fa-f0-9]{2}$";
    public String hexRegEx1 = "^[A-Fa-f0-9]$";
    public String hexRegEx2 = "^[A-Fa-f0-9]{2}$";
    private String decRegEx = "^-?[0-9]*$";

    /**
     * Default no-thrills constructor
     */
    public Assembler() {
    }

    /**
     * This constructor is the one that begins all the assembly work.
     * Here we initialize the scanners for the input text, the boolean variables,
     * and little else.
     * @param docText The assembly code that was typed in the editor.
     */
    public Assembler(String docText) {


        this.setFoundSymbol(false);
        this.setCode(docText);
        //Scanner used for pass-2
        scan = new Scanner(this.getCode());
        scan.useDelimiter(System.getProperty("line.separator"));

        //Scanner used for pass-1
        sym = new Scanner(this.getCode());
        sym.useDelimiter(System.getProperty("line.separator"));

        this.setErrors(new ArrayList<String>());
        //start pass one
        this.passOne();

        //if no errors, then we continue with pass two, otherwise why bother
        if (!this.getError()) {
            this.pass_two();
        }
        scan.close();
        sym.close();
    }

    /**
     * This is where pass one of the assembler does it's work. The only byte code
     * written is that for the db, org, and bss instructions. These are needed
     * here because they alter the location counter, which is used to keep track
     * of symbol locations.
     * This iterates through each line in the assembler text until we reach the
     * end of the text. Any symbols found are put in the symbol table. Any
     * errors found are placed in the errors arraylist.
     */
    private void passOne() {
    	// Team Alpha edit:
    	// added debug logging here
        logger.debug("Entering pass one execution");

        // Initialize the instructions array which is used to pass to the
        // memory table so that the values are updated.
        this.setInstructions(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
                });

        // lets initialize the symbol tables and such
        this.initialize_tables();

        // LineNumber keeps track of what line we are at
        this.setLineNumber(0);

        boolean more_input = true;
        @SuppressWarnings("unused")
		String line, symbol, literal, opcode = null;
        @SuppressWarnings("unused")
		int length, value, type;
        @SuppressWarnings("unused")
		final int END_STATEMENT = -2;

        this.setLocation_counter(0);

        // Iterate through input text until the end of file
        while (more_input) {

            this.setFoundSymbol(false);
            line = read_next_line(sym);
            this.setLineNumber(this.getLineNumber() + 1);

            // hard tabs were causing problems so we decided to get rid of them
            line = line.replaceAll("\t", " ");

            // length of each instruction is 2 bytes
            length = 2;
            type = 0;
            String[] operands = null;

            // if the line is a comment then we don't even bother assembling it
            if (line != null && line_is_not_comment(line) && !line.equals("")) {
                if (line.contains(";")) {
                    int index = line.indexOf(';');
                    logger.debug("Comment found at index: " + index);
                    line = line.substring(0, index);
                }

                // lets check for labels
                symbol = check_for_symbol(line);

                // if symbol found add it to the symbol table in lower case
                if (symbol != null) {
                    this.setFoundSymbol(true);
                    // perseus:
                    // re-enabled to allow labels to get the right location
                    // when not "org"
                    enter_new_symbol(symbol.toLowerCase(), this.getLocation_counter());
                    int index = line.indexOf(":");
                    line = line.substring(index + 1);
                }

                // look for operands
                operands = parseOperands(line);

                logger.debug("Now we get the opcode...");
                // now determine the opcode type. -1 means illegal opcode
                opcode = extract_opcode(line);
                logger.debug("Extracted the opcode..." + opcode);
                // type = search_opcode_table(opcode, operands);
                // logger.debug("The type of opCode is: " + type);

                // depending on what the opcode is, we either increment
                // location counter by two or by some other value

                this.increaseLocationCounter(opcode, operands);

                logger.debug("now at memory location: " + this.getLocation_counter());
                // perseus
                // added this to handle updating location counter on labels 
                // with an org opcode.
                if (symbol != null && opcode.equalsIgnoreCase("org")) {
                    enter_new_symbol(symbol.toLowerCase(), this.getLocation_counter());
                }
                
                if (!sym.hasNextLine()) {
                    more_input = false;
                }
            // sort_literal_table();
            // remove_redundant_literals();

            }

        }

        this.setLocation_counter(0);

    	// Team Alpha edit:
    	// added debug logging here
        logger.debug("Pass one execution complete...");
    }

    /**
     * Pass Two of the assembler. Iterate through the input text again, and sub
     * in the memory locations of all the symbols found. Also write the code
     * for the instructions in this pass.
     */
    private void pass_two() {
        logger.debug("Entering pass two execution");

        // reinitialize the instructions array. if this pass is done right
        // the array will look identical to the first pass except with all
        // byte code subbed in
        this.setInstructions(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
                });

        boolean more_input = true;
        @SuppressWarnings("unused")
		String line, symbol, literal, opcode = null;
        @SuppressWarnings("unused")
		int length, value, type;
        @SuppressWarnings("unused")
		final int END_STATEMENT = -2;

        this.setLineNumber(0);
        this.setLocation_counter(0);
        // initialize_tables();

        // iterate line by line
        while (more_input) {

            line = read_next_line();

            // keep track of the line number for error reporting
            this.setLineNumber(this.getLineNumber() + 1);
            line = line.replaceAll("\t", " ");
            length = 2;
            type = 0;
            String[] operands = null;

            // if line is not a comment continue, if there's a comment somewhere
            // in the line then we strip it
            if (line != null && line_is_not_comment(line) && !line.equals("")) {
                if (line.contains(";")) {
                    int index = line.indexOf(';');
                    logger.debug("Comment found at index: " + index);
                    line = line.substring(0, index);
                }

                // look for symbols
                symbol = check_for_symbol(line);

                if (symbol != null) {
                    this.setFoundSymbol(true);
                    logger.debug("removing the symbol");
                    int index = line.indexOf(":");
                    line = line.substring(index + 1);
                }
                operands = parseOperands(line);

                // this is where we parse out the operands and if it's a symbol
                // we sub it with the correct memory location  
                if (operands != null) {
                    this.subSymbolLocation(operands);
                }
                logger.debug("Now we gets the opcode...");
                // now determine the opcode type. -1 means illegal opcode
                opcode = extract_opcode(line);
                logger.debug("Extracted the opcode..." + opcode);
                // type = search_opcode_table(opcode, operands);
                // logger.debug("The type of opCode is: " + type);

                // lets write out the byte code
                writeFinalFile(opcode, operands, this.getLocation_counter());

                // increase location counter based on what instruction was read
                if (!opcode.trim().equals("db") && !opcode.trim().equals("org") && !opcode.equals("") && opcode != null && !opcode.equals("bss")) {
                    this.setLocation_counter(this.getLocation_counter() + length);
                    logger.debug("opcode was not db, or org");
                }
                logger.debug("now at memory location: " + this.getLocation_counter());
                if (!scan.hasNextLine()) {
                    more_input = false;
                }
            // sort_literal_table();
            // remove_redundant_literals();

            }

        }

    	// Team Alpha edit:
    	// added debug logging here
        logger.debug("Pass two execution complete...");
    }

    /**
     * Reads the next line in the input text.
     * @return A line of text.
     */
    private String read_next_line() {
        logger.debug("Reading the next line...");
        String line = "";

        if (scan.hasNextLine()) {
            line = scan.nextLine().trim();
            return line;
        }
        return null;
    }

    /**
     * Reads the next line in the input text.
     * @param sym2 The scanner used for pass one.
     * @return A string of text.
     */
    private String read_next_line(Scanner sym2) {
        logger.debug("Reading the next line...");
        String line = "";

        if (sym.hasNextLine()) {
            line = sym.nextLine().trim();
            // hard tabs were causing problems so we decided to get rid of them
            line = line.replaceAll("\t", " ");
            return line;
        }
        return null;
    }

    /**
     * Used by pass one to increase the location counter based on what instruct-
     * was read.
     * @param opcode The opcode extracted from the line.
     * @param operands An array of operands.
     */
    private void increaseLocationCounter(String opcode, String[] operands) {
        if (opcode.equalsIgnoreCase("bss")) {
            writeBss(operands, this.getLocation_counter());
        }
        if (opcode.equalsIgnoreCase("db")) {
            writeDb(operands, this.getLocation_counter());
            logger.debug("increaseLocationCounter: this.getLocation_counter()="+this.getLocation_counter());
        }
        if (opcode.equalsIgnoreCase("halt")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("org")) {
            writeOrg(operands, this.getLocation_counter());
        }
        if (opcode.equalsIgnoreCase("load")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("store")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("move")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("addi")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        // Team Alpha edit:
        // removing addf command, replacing with stack-frame commands
        // at end of list; preserving original code in this comment.
        /*if (opcode.equalsIgnoreCase("addf")) {
         *   this.setLocation_counter(this.getLocation_counter() + 2);
         *}
         */
        if (opcode.equalsIgnoreCase("or")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("xor")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("and")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("ror")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("jmpEQ")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("jmpLE")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("jmp")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        // Team Alpha edit:
        // new op-codes
        if (opcode.equalsIgnoreCase("call")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("ret")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("mcall")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("mret")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("push")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("pop")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("srload")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("brload")) {
            this.setLocation_counter(this.getLocation_counter() + 2);
        }
        if (opcode.equalsIgnoreCase("prog")) {
        	writeProg(operands, this.getLocation_counter());
        }
    }

    /**
     * Initialize the symbol, literal, and instruction tables.
     */
    private void initialize_tables() {
        logger.debug("Initiazling the tables...");
        this.setSymbolTable(new Hashtable<String, Integer>());
        this.setLiteralTable(new LinkedHashSet<String>());
        // populate the opcode table - array: "first char", "second char",
        // "third char", "fourth char", "opcode type"
        Hashtable<String, Integer> temp = new Hashtable<String, Integer>();
        temp.put("db", new Integer(0));
        temp.put("halt", new Integer(1));
        temp.put("org", new Integer(2)); // only expect an address
        temp.put("load", new Integer(3));
        temp.put("store", new Integer(4));
        temp.put("move", new Integer(5));
        temp.put("addi", new Integer(6));
        // Team Alpha edit:
        // removing addf command, replacing with stack-frame commands
        // at end of list; preserving original code in this comment.
        // to restore: uncomment and increment all following entries
        // new Integer(x) value.
        //temp.put("addf", new Integer(7));
        temp.put("or", new Integer(7));
        temp.put("and", new Integer(8));
        temp.put("xor", new Integer(9));
        temp.put("ror", new Integer(10));
        temp.put("jmpEQ", new Integer(11));
        temp.put("jmpLE", new Integer(12));
        temp.put("jmp", new Integer(13));
        
		// Team Alpha edit:
		// new opcodes/directive
        temp.put("call", new Integer(14));
        temp.put("ret", new Integer(15));
        temp.put("mcall", new Integer(16));
        temp.put("mret", new Integer(17));
        temp.put("push", new Integer(18));
        temp.put("pop", new Integer(19));
        temp.put("srload", new Integer(20));
        temp.put("brload", new Integer(21));
		temp.put("prog", new Integer(22));
		// end Team Alpha edit
		
        this.setOpcodeTable(temp);
    }

    /**
     * Check the line for a label. 
	 * A label has the following syntax: 
	 *     <LabelName>: <instruction>
	 *
     * @param line The line of assembly code.
     * @return The symbol if it is found, otherwise returns null.
     */
    private String check_for_symbol(String line) {
        logger.debug("Checking if line has a symbol: " + line);

        int symIndex = line.indexOf(":");
        String res = "";
        if (symIndex != -1) {
            logger.debug("Line had a symbol!");
            res = line.substring(0, symIndex);
            return res;
        }
        return null;
    }

    /**
     * Checks to see if the line is not a comment.
	 * If it is a comment, there will be a ';' at the beginning of the line.
	 *
     * @param line The line of assembly code.
     * @return True if the line is a comment, otherwise false.
     */
    private boolean line_is_not_comment(String line) {
        
        logger.debug("Checking if the line is not a comment...");
        if (line != null && !line.equals("")) {
            if (line.charAt(0) != ';') {
                logger.debug("This line was not a comment: " + line);
                return true;
            }

        }
        logger.debug("returning false");
        return false;
    }

    /**
     * Adds the found symbol to the symbol table along with it's corresponding memory address.
	 *
     * @param symbol The symbol found.
     * @param location_counter The memory location of the symbol.
     */
    private void enter_new_symbol(String symbol, int location_counter) {
        
        logger.debug("Adding symbol to table: symbol: " + symbol + ", location: " + location_counter);
        this.getSymbolTable().put(symbol, location_counter);
    }

    /**
     * Parses a line of assembly code, and extracts the operands and sticks them in a String array.
	 *
     * @param line The line of assembly code.
     * @return A string array of operands found.
     */
    private String[] parseOperands(String line) {
        // taking out the label
        logger.debug("Going to parse the operands...");

        if (line.equals("")) {
            logger.debug("no more after symbol");
            return null;
        }

        // taking out multiple spaces in between operands and stuff
        line = line.trim();
        logger.debug("trimmed white spaces: " + line);

        // take out the opcode, leaving just the operands
        int index = line.indexOf(" ");
        logger.debug("The index of the first space is: " + index);
		
        // int index2 = line.indexOf("\t");
        // logger.debug("The index of the first tab is: " + index2);

        if (index == -1) {
            logger.debug("line has nothing but the opcode");
            return null;
        }

        line = line.substring(index);
        logger.debug("took out the opcode, leaving operands: " + line);

        line = line.trim();

        // split a line into operands
        String[] operands = line.split(",");

        for (int i = 0; i < operands.length; i++) {
            logger.debug("after the split we got this: operands[" + i + "] = " + operands[i]);
            operands[i] = operands[i].trim();

        }
        return operands;
    }

    /**
     *
     * @param operands
     */
    private void subSymbolLocation(String[] operands) {
        
        for (int i = 0; i < operands.length; i++) {
            if (operands[i].contains("[")) {
                if (this.getSymbolTable().containsKey(operands[i].substring(1, operands[i].length() - 1).toLowerCase())) {
                    logger.debug("operands[" + i + "], is a symbol, going to sub in the location");
                    operands[i] = "[" + this.getSymbolTable().get(operands[i].substring(1, operands[i].length() - 1).toLowerCase()) + "]";
                    logger.debug("the operands element is now: " + operands[i]);

                    this.setOpLabel(true);
                }

            } else {
                if (this.getSymbolTable().containsKey(operands[i].toLowerCase())) {
                    logger.debug("operands[" + i + "], is a symbol, going to sub in the location");
                    operands[i] = this.getSymbolTable().get(operands[i].toLowerCase()) + "";
                    logger.debug("the operands element is now: " + operands[i]);
                    this.setOpLabel(true);
                }

            }
        }
    }

    private void writeBss(String[] operands, int location_counter) {
        logger.debug("Got the bss opcode so we have to skip assigned storage");        
        if (this.getFoundSymbol()) {
            if (operands[0].contains("0x")) {
            	try{
            		int skip = Integer.parseInt(operands[0].substring(2), 16);
            		this.setLocation_counter(this.getLocation_counter() + skip);
            	}
            	catch (NumberFormatException nfe){
                	this.setError(true);
                	this.getErrors().add("Line " + this.getLineNumber() + ": Not an immediate. Expected: number in Hex format");
                }
            	
            } else if (operands[0].matches("[0-9]*")) {
            	try{
            		int skip = Integer.parseInt(operands[0]);
            		this.setLocation_counter(this.getLocation_counter() + skip);
            	}catch (NumberFormatException nfe){
                	this.setError(true);
                	this.getErrors().add("Line " + this.getLineNumber() + ": Not an immediate. Expected: number in decimal format");
                }
            }
        } else {
            // we have an error since we expect a label in front
            this.setError(true);
            this.getErrors().add("Line " + this.getLineNumber() + ": Label not Found. Expected a Label");
        }
    }

    private void writeDb(String[] operands, int location) {
        logger.debug("Got the db opcode so we have to store each argument");
        byte[] temp = this.getInstructions();
        String hexByte = "";
        @SuppressWarnings("unused")
		String strMatch = "[a-fA-F]";
        // iterate through the operands, need to also be able to handle strings
        for (int i = 0; i < operands.length; i++) {
            logger.debug("storing argument: " + operands[i] + " , at location: " + location);
            
            if (operands[i].contains("\"")) {
            	//operand is a string
            	int quoteIndex1 = operands[i].indexOf("\"");
            	if (operands[i].substring(quoteIndex1+1).contains("\"")){
            		//must have end quote
            		logger.debug("db argument is a string");
                    String str = operands[i].substring(1, operands[i].length() - 1);
                    logger.debug("The chopped string is: " + str);
                    for (int j = 0; j < str.length(); j++) {
                        int character = str.charAt(j);
                        String cheat = character + "";
                        logger.debug("The ascii code as a string is: " + cheat);
                        try{
                        	byte hex = (byte) Integer.parseInt(cheat);	
                        	logger.debug("The byte is: " + hex);
                            temp[location++] = hex;	
                        } catch (NumberFormatException nfe) {
                        	this.setError(true);
                        	this.getErrors().add("Line " + this.getLineNumber() + ": Not an immediate. Expected: number,string");
                        }
                        
                    }
                
                } else {
            		//error, needs end quote
            		this.setError(true);
            		this.getErrors().add("Line " + this.getLineNumber() + ": Unexpected end of string. Expected: \"");
            	}

            } else {
                byte hex;
                logger.debug("the db argument was a number");
                //if (operands[i].contains(" +")){
                if (operands[i].contains("0x")) {
                	logger.debug("it was a hex number");
                    hexByte = operands[i].substring(2);
                    if (operands[i].contains(" ")) {
                    	this.setError(true);
                    	this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error.  Expected ','");
                    } else {
                    	try {
                    		hex = (byte) Integer.parseInt(hexByte, 16);
                        	logger.debug("Going to store the number: " + hex);
                            temp[location] = hex;
                            logger.debug("Number stored at location: " + location);
                            location += 1;
                        } catch (NumberFormatException nfe) {
                           	this.setError(true);
                           	this.getErrors().add("Line " + this.getLineNumber() + ": Not an immediate. Expected: number,string");
                        }
                        	
                    }
                    
                } else {
                	logger.debug("it was a decimal number");
                    hexByte = operands[i];
                    if (operands[i].contains(" ")) {
                    	logger.debug("error found");
                        this.setError(true);
                        this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error.  Expected ','");
                    } else {
                    	try {
                    		hex = (byte) Integer.parseInt(hexByte);
                        	logger.debug("Going to store the number: " + hex);
                            temp[location] = hex;
                            logger.debug("Number stored at location: " + location);
                            location += 1;
                        } catch (NumberFormatException nfe) {
                    		this.setError(true);
                    		this.getErrors().add("Line " + this.getLineNumber() + ": Not an immediate. Expected: number,string");
                    	}	
                    }
                }
                	
                    
                //}
                //else{
                	//error occurred - non-comma delimited
                	//this.setError(true);
                	//this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error.  Expected ','");
                //}
                }
        }
        this.setLocation_counter(location);
        this.setInstructions(temp);

    }

    private void writeHalt(String opcode, int location) {
        
        logger.debug("Got the halt opcode, so we are going to write it to the array at location: " + location);
        byte[] temp = this.getInstructions();
        String hexByte1 = "0xC0";
        byte hex1 = this.extractNumber(hexByte1);
        temp[location] = hex1;
        byte hex2 = 0;
        temp[location + 2] = hex2;
        this.setInstructions(temp);
        logger.debug("Finished writing the halt instruction");
    }

    private void writeOrg(String[] operands, int location) {
        
        logger.debug("Got the org opcode...setting the location address to: " + operands[0]);
        int temp = 0;

        if (operands[0].matches(hexRegEx)) {
        	try {
        		temp = Integer.parseInt(operands[0].substring(2), 16);
        	} catch (NumberFormatException nfe) {
            	this.setError(true);
            	this.getErrors().add("Line " + this.getLineNumber() + ": Not an immediate. Expected: number,string");
            }
        } else if (operands[0].matches("\\d*")) {
        	try {
        		temp = Integer.parseInt(operands[0]);
        	} catch (NumberFormatException nfe) {
            	this.setError(true);
            	this.getErrors().add("Line " + this.getLineNumber() + ": Not an immediate. Expected: number,string");
            }
        } else {
            // have an invalid address; throw an error
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Invalid Argument " + operands[0] + ", expected a memory address.");
        }
        // perseus:
        // this line of code was causing
        // negative integer index values
        // by casting to a byte when
        // setLocation_counter() wants
        // an integer
        // Original line of code was: 
        // this.setLocation_counter((byte) temp);
        this.setLocation_counter(temp);
        logger.debug("set the location counter to :" + this.getLocation_counter());
    }

    private void writeFinalFile(String opcode, String[] operands, int location) {
        
        if (opcode.equalsIgnoreCase("bss")) {
            writeBss(operands, location);
        } else if (opcode.equalsIgnoreCase("db")) {
            writeDb(operands, location);
        } else if (opcode.equalsIgnoreCase("halt")) {
            writeHalt(opcode, location);
        } else if (opcode.equalsIgnoreCase("org")) {
            writeOrg(operands, location);
        } else if (opcode.equalsIgnoreCase("load")) {
            writeLoad(operands, location);
        } else if (opcode.equalsIgnoreCase("store")) {
            writeStore(operands, location);
        } else if (opcode.equalsIgnoreCase("move")) {
            writeMove(operands, location);
        } else if (opcode.equalsIgnoreCase("addi")) {
            writeAddI(operands, location);
        }
        // Team Alpha:
        // again, removing the float addition and adding
        // the stack frame instructions.
        // Original code preserved here...
        /* else if (opcode.equalsIgnoreCase("addf")) {
            writeAddF(operands, location);
        }*/
          else if (opcode.equalsIgnoreCase("or")) {
            writeOr(operands, location);
        } else if (opcode.equalsIgnoreCase("xor")) {
            writeXor(operands, location);
        } else if (opcode.equalsIgnoreCase("and")) {
            writeAnd(operands, location);
        } else if (opcode.equalsIgnoreCase("ror")) {
            writeROR(operands, location);
        } else if (opcode.equalsIgnoreCase("jmpEQ")) {
            writeJmpEQ(operands, location);
        } else if (opcode.equalsIgnoreCase("jmpLE")) {
            writeJmpLE(operands, location);
        } else if (opcode.equalsIgnoreCase("jmp")) {
            writeJmp(operands, location);
            
        // Team Alpha edit:
        // new op-codes
        } else if (opcode.equalsIgnoreCase("call")) {
            writeCall(operands, location);
        } else if (opcode.equalsIgnoreCase("ret")) {
            writeRet(operands, location);
        } else if (opcode.equalsIgnoreCase("mcall")) {
            writeMCall(operands, location);
        } else if (opcode.equalsIgnoreCase("mret")) {
            writeMRet(operands, location);
        } else if (opcode.equalsIgnoreCase("push")) {
            writePush(operands, location);
        } else if (opcode.equalsIgnoreCase("pop")) {
            writePop(operands, location);
        } else if (opcode.equalsIgnoreCase("srload")) {
            writeStackRelLoad(operands, location);
        } else if (opcode.equalsIgnoreCase("brload")) {
            writeBaseRelLoad(operands, location);
        } else if (opcode.equalsIgnoreCase("prog")) {
            writeProg(operands, location);
        // end Team Alpha edit
            
        } else if (!opcode.equalsIgnoreCase("")) {
            // has to be an invalid opcode
            this.setError(true);
            this.getErrors().add("Line " + this.getLineNumber() + ": Invalid Instruction: " + opcode + ".");
        }
    }

    private void writeROR(String[] operands, int location) {
        // looks like AROX
        // ROR R,X
        logger.debug("Found a ROR opcode");
        byte[] temp = this.getInstructions();

        if (operands[0].contains("R") || operands[0].contains("r")) {
            // First operand is a register
            // second operand is the number of times rotated

            String hex1 = "0xA" + operands[0].charAt(1);
            byte byte1 = extractNumber(hex1);
            logger.debug("The first byte looks like: " + byte1);
            temp[location++] = byte1;

            // second operand is number times rotated (presumably in decimal)
            // make sure it's not empty
            byte byte2 = 0;
            if (operands[1].matches(decRegEx)) {
                byte2 = extractNumber(operands[1]);
                logger.debug("TimesRotated = " + byte2);
                temp[location] = byte2;
            } else {
                // invalid 2nd argument
                this.setError(true);
                this.getErrors().add(
                         "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[1] + ", not a number.");
            }

        } else {
            // invalid argument
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", expected a register id.");
        }
    }

    private void writeAddI(String[] operands, int location) {
        // looks like 5RRR where R = register id
        logger.debug("We gots an addi opcode!");
        byte[] temp = this.getInstructions();

        if (operands[0].contains("R") || operands[0].contains("r")) {
            if (operands[1].contains("R") || operands[1].contains("r")) {
                if (operands[2].contains("R") || operands[2].contains("r")) {
                    String hex1 = "0x5" + operands[0].substring(1);
                    byte byte1 = extractNumber(hex1);
                    logger.debug("The first byte looks like: " + byte1);
                    temp[location++] = byte1;

                    String hex2 = "0x" + operands[1].substring(1) + operands[2].substring(1);
                    byte byte2 = extractNumber(hex2);
                    logger.debug("The second byte looks like: " + byte2);
                    temp[location] = byte2;
                } else {
                    // invalid argument
                    this.setError(true);
                    this.getErrors().add(
                            "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[2] + ", expected a register id.");
                }
            } else {
                // error
                // error
                // invalid argument
                this.setError(true);
                this.getErrors().add(
                        "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[1] + ", expected a register id.");
            }
        } else {
            // error
            // error
            // invalid argument
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", expected a register id.");
        }

    }

    private void writeOr(String[] operands, int location) {
        // looks like 7RRR where R = register id
        logger.debug("We gots an OR opcode!");
        byte[] temp = this.getInstructions();

        if (operands[0].contains("R") || operands[0].contains("r")) {
            if (operands[1].contains("R") || operands[1].contains("r")) {
                if (operands[2].contains("R") || operands[2].contains("r")) {
                    String hex1 = "0x7" + operands[0].substring(1);
                    byte byte1 = extractNumber(hex1);
                    logger.debug("The first byte looks like: " + byte1);
                    temp[location++] = byte1;

                    String hex2 = "0x" + operands[1].substring(1) + operands[2].substring(1);
                    byte byte2 = extractNumber(hex2);
                    logger.debug("The second byte looks like: " + byte2);
                    temp[location] = byte2;
                } else {
                    // invalid argument
                    this.setError(true);
                    this.getErrors().add(
                            "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[2] + ", expected a register id.");
                }
            } else {
                // error
                // error
                // invalid argument
                this.setError(true);
                this.getErrors().add(
                        "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[1] + ", expected a register id.");
            }
        } else {
            // error
            // error
            // invalid argument
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", expected a register id.");
        }

    }

    private void writeAnd(String[] operands, int location) {
        // looks like 8RRR where R = register id
        logger.debug("We gots an AND opcode!");
        byte[] temp = this.getInstructions();

        if (operands[0].contains("R") || operands[0].contains("r")) {
            if (operands[1].contains("R") || operands[1].contains("r")) {
                if (operands[2].contains("R") || operands[2].contains("r")) {
                    String hex1 = "0x8" + operands[0].substring(1);
                    byte byte1 = extractNumber(hex1);
                    logger.debug("The first byte looks like: " + byte1);
                    temp[location++] = byte1;

                    String hex2 = "0x" + operands[1].substring(1) + operands[2].substring(1);
                    byte byte2 = extractNumber(hex2);
                    logger.debug("The second byte looks like: " + byte2);
                    temp[location] = byte2;
                } else {
                    // invalid argument
                    this.setError(true);
                    this.getErrors().add(
                            "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[2] + ", expected a register id.");
                }
            } else {
                // error
                // error
                // invalid argument
                this.setError(true);
                this.getErrors().add(
                        "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[1] + ", expected a register id.");
            }
        } else {
            // error
            // error
            // invalid argument
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", expected a register id.");
        }

    }

    // Team Alpha
    // DEPRECATED: left for future re-implementation.
    @SuppressWarnings("unused")
	private void writeAddF(String[] operands, int location) {
        // looks like 6RRR where R = register id
        logger.debug("We gots an addf opcode!");
        byte[] temp = this.getInstructions();

        if (operands[0].contains("R") || operands[0].contains("r")) {
            if (operands[1].contains("R") || operands[1].contains("r")) {
                if (operands[2].contains("R") || operands[2].contains("r")) {
                    String hex1 = "0x6" + operands[0].substring(1);
                    byte byte1 = extractNumber(hex1);
                    logger.debug("The first byte looks like: " + byte1);
                    temp[location++] = byte1;

                    String hex2 = "0x" + operands[1].substring(1) + operands[2].substring(1);
                    byte byte2 = extractNumber(hex2);
                    logger.debug("The second byte looks like: " + byte2);
                    temp[location] = byte2;
                } else {
                    // invalid argument
                    this.setError(true);
                    this.getErrors().add(
                            "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[2] + ", expected a register id.");
                }
            } else {
                // error
                // error
                // invalid argument
                this.setError(true);
                this.getErrors().add(
                        "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[1] + ", expected a register id.");
            }
        } else {
            // error
            // error
            // invalid argument
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", expected a register id.");

        }

    }

    private void writeXor(String[] operands, int location) {
        // looks like 9RRR where R = register id
        logger.debug("We gots an xor opcode!");
        byte[] temp = this.getInstructions();

        if (operands[0].contains("R") || operands[0].contains("r")) {
            if (operands[1].contains("R") || operands[1].contains("r")) {
                if (operands[2].contains("R") || operands[2].contains("r")) {
                    String hex1 = "0x9" + operands[0].substring(1);
                    byte byte1 = extractNumber(hex1);
                    logger.debug("The first byte looks like: " + byte1);
                    temp[location++] = byte1;

                    String hex2 = "0x" + operands[1].substring(1) + operands[2].substring(1);
                    byte byte2 = extractNumber(hex2);
                    logger.debug("The second byte looks like: " + byte2);
                    temp[location] = byte2;
                } else {
                    // invalid argument
                    this.setError(true);
                    this.getErrors().add(
                            "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[2] + ", expected a register id.");
                }
            } else {
                // error
                // error
                // invalid argument
                this.setError(true);
                this.getErrors().add(
                        "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[1] + ", expected a register id.");
            }
        } else {
            // error
            // error
            // invalid argument
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", expected a register id.");
        }

    }

    private void writeMove(String[] operands, int location) {
        // looks like 40RR where R = register id

        byte[] temp = this.getInstructions();
        logger.debug("We gots a move opcode!");
        if (operands[0].contains("R") || operands[0].contains("r")) {
            if (operands[0].contains("R") || operands[0].contains("r")) {
                String hex1 = "0x40";
                byte byte1 = extractNumber(hex1);
                logger.debug("The first byte looks like: " + byte1);
                temp[location++] = byte1;

                String hex2 = "0x" + operands[1].substring(1) + operands[0].substring(1);
                byte byte2 = extractNumber(hex2);
                logger.debug("The second byte looks like: " + byte2);
                temp[location] = byte2;

            } else {
                // error
                // error
                // invalid argument
                this.setError(true);
                this.getErrors().add(
                        "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[1] + ", expected a register id.");
            }
        } else {
            // error
            // error
            // invalid argument
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", expected a register id.");
        }
    }
    
    /*
     * Team Alpha
     * Added additional methods to write the new stack frame op-codes
     */
    /**
     * This method parses a line of JSimpleSim assembler instructions into the byte form of the Call op-code.
     * Call instructions are of the form: 60XY
     * Where XY is an address in Main Memory where the first byte of the first instruction of the called
     * subprogram resides.
     * 
     * @param operands
     * @param location
     */
    private void writeCall(String[] operands, int location) {
        logger.debug("Found a Call opcode");
        
        // retrieve the main memory array
        byte[] temp = this.getInstructions();
        
        // initialize our two bytes of instruction
        byte byte1, byte2;
        
        // first byte of this instruction is always the same
        String hex1 = "60";
        
        // convert the string to a integer using base 16
        // and then cast to a byte for storage in main memory array
        byte1 = (byte) Integer.parseInt(hex1, 16);
        logger.debug("The first byte looks like: " + byte1);
        
        // store the byte and increment the location counter
        temp[location++] = byte1;

        // operand is a memory address, but it might be hex or decimal
        if (operands[0].matches(hexRegEx)) {
        	// operand is hex format
        	// convert the string to a integer using base 16
            // and then cast to a byte for storage in main memory array
            byte2 = (byte) Integer.parseInt(operands[0].substring(2), 16);
        } else if (operands[0].matches(decRegEx)) {
        	// operand is decimal format
        	// convert the string to a integer
            // and then cast to a byte for storage in main memory array
            byte2 = (byte) Integer.parseInt(operands[0]);
        } else {
            // invalid argument
            this.setError(true);
            this.getErrors().add("Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", not a number.");
            return;
        }
        // logging the byte
        logger.debug("The second byte looks like: " + byte2);

        // store the byte
        temp[location] = byte2;
        
        // Team Alpha uncertainty:
        // only writeDb uses this command, not sure how the instructions array
        // is getting updated without it...so we are including it
        this.setInstructions(temp);
    }

    /**
     * This method parses a line of JSimpleSim assembler instructions into the byte form of the Return op-code.
     * Return instructions are of the form: 6100
     * 
     * @param operands
     * @param location
     */
    private void writeRet(String[] operands, int location) {
        logger.debug("Found a Return opcode");
        
        // retrieve the main memory array
        byte[] temp = this.getInstructions();
        
        // initialize our two bytes of instruction
        byte byte1, byte2;
        
        // first byte of this instruction is always the same
        String hex1 = "61";
        
        // convert the string to a integer using base 16
        // and then cast to a byte for storage in main memory array
        byte1 = (byte) Integer.parseInt(hex1, 16);
        logger.debug("The first byte looks like: " + byte1);
        
        // store the byte and increment the location counter
        temp[location++] = byte1;
        
        // second byte of this instruction is always the same
        // cast integer zero into a byte to get 0x00
        byte2 = (byte) 0;
        logger.debug("The second byte looks like: " + byte2);

        // store the byte
        temp[location] = byte2;
        
        // Team Alpha uncertainty:
        // only writeDb uses this command, not sure how the instructions array
        // is getting updated without it...so we are including it
        this.setInstructions(temp);
    }

    /**
     * This method parses a line of JSimpleSim assembler instructions into the byte form of the MACRO Call op-code.
     * MACRO Call instructions are of the form: 62XY
     * Where XY is an address in Main Memory where the first byte of the first instruction of the called
     * subprogram resides.
     * 
     * @param operands
     * @param location
     */
    private void writeMCall(String[] operands, int location) {
        logger.debug("Found a MACRO Call opcode");
        
        // retrieve the main memory array
        byte[] temp = this.getInstructions();
        
        // initialize our two bytes of instruction
        byte byte1, byte2;
        
        // first byte of this instruction is always the same
        String hex1 = "62";
        
        // convert the string to a integer using base 16
        // and then cast to a byte for storage in main memory array
        byte1 = (byte) Integer.parseInt(hex1, 16);
        logger.debug("The first byte looks like: " + byte1);
        
        // store the byte and increment the location counter
        temp[location++] = byte1;

        // operand is a memory address, but it might be hex or decimal
        if (operands[0].matches(hexRegEx)) {
        	// operand is hex format
        	// convert the string to a integer using base 16
            // and then cast to a byte for storage in main memory array
            byte2 = (byte) Integer.parseInt(operands[0].substring(2), 16);
        } else if (operands[0].matches(decRegEx)) {
        	// operand is decimal format
        	// convert the string to a integer
            // and then cast to a byte for storage in main memory array
            byte2 = (byte) Integer.parseInt(operands[0]);
        } else {
            // invalid argument
            this.setError(true);
            this.getErrors().add("Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", not a number.");
            return;
        }
        // logging the byte
        logger.debug("The second byte looks like: " + byte2);

        // store the byte
        temp[location] = byte2;
        
        // Team Alpha uncertainty:
        // only writeDb uses this command, not sure how the instructions array
        // is getting updated without it...so we are including it
        this.setInstructions(temp);
    }

    /**
     * This method parses a line of JSimpleSim assembler instructions into the byte form of the MACRO Return op-code.
     * MACRO Return instructions are of the form: 6300
     * 
     * @param operands
     * @param location
     */
    private void writeMRet(String[] operands, int location) {
        logger.debug("Found a MACRO Return opcode");
        
        // retrieve the main memory array
        byte[] temp = this.getInstructions();
        
        // initialize our two bytes of instruction
        byte byte1, byte2;
        
        // first byte of this instruction is always the same
        String hex1 = "63";
        
        // convert the string to a integer using base 16
        // and then cast to a byte for storage in main memory array
        byte1 = (byte) Integer.parseInt(hex1, 16);
        logger.debug("The first byte looks like: " + byte1);
        
        // store the byte and increment the location counter
        temp[location++] = byte1;
        
        // second byte of this instruction is always the same
        // cast integer zero into a byte to get 0x00
        byte2 = (byte) 0;
        logger.debug("The second byte looks like: " + byte2);

        // store the byte
        temp[location] = byte2;
        
        // Team Alpha uncertainty:
        // only writeDb uses this command, not sure how the instructions array
        // is getting updated without it...so we are including it
        this.setInstructions(temp);
    }

    /**
     * This method parses a line of JSimpleSim assembler instructions into the byte form of the Push op-code.
     * Push instructions are of the form: 640R
     * Where R is the identifier of the register which contains the value to be pushed onto the stack.
     * 
     * @param operands
     * @param location
     */
    private void writePush(String[] operands, int location) {
        logger.debug("Found a Push opcode");
        
        // retrieve the main memory array
        byte[] temp = this.getInstructions();
        
        // initialize our two bytes of instruction
        byte byte1, byte2;
        
        // first byte of this instruction is always the same
        String hex1 = "64";
        
        // convert the string to a integer using base 16
        // and then cast to a byte for storage in main memory array
        byte1 = (byte) Integer.parseInt(hex1, 16);
        logger.debug("The first byte looks like: " + byte1);
        
        // store the byte and increment the location counter
        temp[location++] = byte1;
        
        // operand is a register
        if (operands[0].contains("R") || operands[0].contains("r")) {
        	// extract the register number and convert it to a byte
        	// we assume the register is always in hex digit form
            hex1 = "0" + operands[0].charAt(1);
            byte2 = (byte) Integer.parseInt(hex1, 16);
            logger.debug("The second byte looks like: " + byte2);
            
            // store the byte
            temp[location] = byte2;
        } else {
            // invalid argument
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", expected a register id.");
        }
        
        // Team Alpha uncertainty:
        // only writeDb uses this command, not sure how the instructions array
        // is getting updated without it...so we are including it
        this.setInstructions(temp);
    }

    /**
     * This method parses a line of JSimpleSim assembler instructions into the byte form of the Pop op-code.
     * Pop instructions are of the form: 650R
     * Where R is the identifier of the register which will contain the value after it is popped off the stack.
     * 
     * @param operands
     * @param location
     */
    private void writePop(String[] operands, int location) {
        logger.debug("Found a Pop opcode");
        
        // retrieve the main memory array
        byte[] temp = this.getInstructions();
        
        // initialize our two bytes of instruction
        byte byte1, byte2;
        
        // first byte of this instruction is always the same
        String hex1 = "65";
        
        // convert the string to a integer using base 16
        // and then cast to a byte for storage in main memory array
        byte1 = (byte) Integer.parseInt(hex1, 16);
        logger.debug("The first byte looks like: " + byte1);
        
        // store the byte and increment the location counter
        temp[location++] = byte1;
        
        // operand is a register
        if (operands[0].contains("R") || operands[0].contains("r")) {
        	// extract the register number and convert it to a byte
        	// we assume the register is always in hex digit form
            hex1 = "0" + operands[0].charAt(1);
            byte2 = (byte) Integer.parseInt(hex1, 16);
            logger.debug("The second byte looks like: " + byte2);
            
            // store the byte
            temp[location] = byte2;
        } else {
            // invalid argument
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", expected a register id.");
        }
        
        // Team Alpha uncertainty:
        // only writeDb uses this command, not sure how the instructions array
        // is getting updated without it...so we are including it
        this.setInstructions(temp);
    }

    /**
     * This method parses a line of JSimpleSim assembler instructions into the byte form of the Stack-Relative Load op-code.
     * Stack-Relative Load instructions are of the form: 66XY
     * Where XY is a hex value used as an offset from the value in register D (Stack Pointer).
     * 
     * @param operands
     * @param location
     */
    private void writeStackRelLoad(String[] operands, int location) {
        logger.debug("Found a Stack-Relative Load opcode");
        
        // retrieve the main memory array
        byte[] temp = this.getInstructions();
        
        // initialize our two bytes of instruction
        byte byte1, byte2;
        
        // first byte of this instruction is always the same
        String hex1 = "66";
        
        // convert the string to a integer using base 16
        // and then cast to a byte for storage in main memory array
        byte1 = (byte) Integer.parseInt(hex1, 16);
        logger.debug("The first byte looks like: " + byte1);
        
        // store the byte and increment the location counter
        temp[location++] = byte1;

        // operand is an offset, but it might be hex or decimal
        if (operands[0].matches(hexRegEx)) {
        	// operand is hex format
        	// convert the string to a integer using base 16
            // and then cast to a byte for storage in main memory array
            byte2 = (byte) Integer.parseInt(operands[0].substring(2), 16);
        } else if (operands[0].matches(decRegEx)) {
        	// operand is decimal format
        	// convert the string to a integer
            // and then cast to a byte for storage in main memory array
            byte2 = (byte) Integer.parseInt(operands[0]);
        } else {
            // invalid argument
            this.setError(true);
            this.getErrors().add("Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", not a number.");
            return;
        }
        // logging the byte
        logger.debug("The second byte looks like: " + byte2);

        // store the byte
        temp[location] = byte2;
        
        // Team Alpha uncertainty:
        // only writeDb uses this command, not sure how the instructions array
        // is getting updated without it...so we are including it
        this.setInstructions(temp);
    }

    /**
     * This method parses a line of JSimpleSim assembler instructions into the byte form of the Base-Relative Load op-code.
     * Base-Relative Load instructions are of the form: 67XY
     * Where XY is a hex value used as an offset from the value in register E (Base Pointer).
     * 
     * @param operands
     * @param location
     */
    private void writeBaseRelLoad(String[] operands, int location) {
        logger.debug("Found a Base-Relative Load opcode");
        
        // retrieve the main memory array
        byte[] temp = this.getInstructions();
        
        // initialize our two bytes of instruction
        byte byte1, byte2;
        
        // first byte of this instruction is always the same
        String hex1 = "67";
        
        // convert the string to a integer using base 16
        // and then cast to a byte for storage in main memory array
        byte1 = (byte) Integer.parseInt(hex1, 16);
        logger.debug("The first byte looks like: " + byte1);
        
        // store the byte and increment the location counter
        temp[location++] = byte1;

        // operand is an offset, but it might be hex or decimal
        if (operands[0].matches(hexRegEx)) {
        	// operand is hex format
        	// convert the string to a integer using base 16
            // and then cast to a byte for storage in main memory array
            byte2 = (byte) Integer.parseInt(operands[0].substring(2), 16);
        } else if (operands[0].matches(decRegEx)) {
        	// operand is decimal format
        	// convert the string to a integer
            // and then cast to a byte for storage in main memory array
            byte2 = (byte) Integer.parseInt(operands[0]);
        } else {
            // invalid argument
            this.setError(true);
            this.getErrors().add("Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", not a number.");
            return;
        }
        // logging the byte
        logger.debug("The second byte looks like: " + byte2);

        // store the byte
        temp[location] = byte2;
        
        // Team Alpha uncertainty:
        // only writeDb uses this command, not sure how the instructions array
        // is getting updated without it...so we are including it
        this.setInstructions(temp);
    }
    
    /**
     * 
     * @param operands
     * @param location
     */
    private void writeProg(String[] operands, int location) {
        // TODO Method stub, finish me Team Alpha!
    }
	// end Team Alpha Edit
    
    /**
     *
     * @return
     */
    public String getCode() {
        return code;
    }

    /**
     *
     * @param code
     */
    public void setCode(String code) {
        this.code = code;
    }

    /**
     *
     * @return
     */
    public Hashtable<String, Integer> getSymbolTable() {
        return symbolTable;
    }

    /**
     *
     * @param symbolTable
     */
    public void setSymbolTable(Hashtable<String, Integer> symbolTable) {
        this.symbolTable = symbolTable;
    }

    /**
     *
     * @return
     */
    public LinkedHashSet<String> getLiteralTable() {
        return literalTable;
    }

    /**
     *
     * @param literalTable
     */
    public void setLiteralTable(LinkedHashSet<String> literalTable) {
        this.literalTable = literalTable;
    }

    private String extract_opcode(String line) {

        String opCode = "";
        logger.debug("looking for the opcode..." + line);
        line = line.replaceAll(" +", " ");
        logger.debug("got rid of multiple white spaces...:" + line);
        int space = line.indexOf(" ");
        int space2 = line.indexOf(" ", space + 1);
        int colon = line.indexOf(":");
        if (colon > space) // in case a colon is used in one of the operands
        {
            colon = -1;
        }
        logger.debug("got the indexes of the blank spaces around opcode: index1 = " + space + ", index2 = " + space2);

        // first case: symbol is the only one on the line
        if (colon != -1 && space == -1) {
            logger.debug("The label name is the only thing present on this line");
            opCode = "";
        } // second case: there is a label and opcode follows label by a space
        else if (space == (colon + 1)) {
            if (space2 != -1) {
                logger.debug("There is a label followed by a space followed by an opcde followed by a space");

                opCode = line.substring(space + 1, space2);
            } else {
                logger.debug("After the label, there is only a space followed by an opcode");
                opCode = line.substring(space + 1);
            }
        } // third case: there is a label, and opcode follows it but no space
        // in
        // between Label:opCode R0, R1, R3
        else if (space != -1) {
            logger.debug("There is a label followed by an opcode with now space: Label:opCode ");
            logger.debug("Space 1 = " + space + ", colon = " + colon);
            opCode = line.substring(colon + 1, space);
        } // 4th case: "Label:opCode" nothing else
        else if (colon != -1 && space == -1) {
            logger.debug("4th Case: 'Label:opCode' and nothing else");
            opCode = line.substring(colon + 1);
        } // 5th case: no label, " addi r1, r2, r3"
        else if (colon == -1 && space != -1 && space2 > space) {
            logger.debug("5th Case: no label, ' addi r1, r2, r2' ");
            opCode = line.substring(space + 1, space2);
        } // 6th case: no label, only opcode, " halt"
        else if ((colon == -1) && (space2 == -1) && space != -1) {
            logger.debug("6th Case: no label, only opcode");
            opCode = line.substring(space + 1);
        } else if (colon == -1 && space2 == -1 && space == -1) {
            opCode = line;
        }
        return opCode;
    }

    private void setOpcodeTable(Hashtable<String, Integer> opcodeTable) {
        this.opcodeTable = opcodeTable;
    }

    @SuppressWarnings("unused")
	private Hashtable<String, Integer> getOpcodeTable() {
        return opcodeTable;
    }

    /**
     *
     * @return
     */
    public byte[] getInstructions() {
        return instructions;
    }

    /**
     *
     * @param instructions
     */
    public void setInstructions(byte[] instructions) {
        this.instructions = instructions;
    }

    private void writeLoad(String[] operands, int location) {
        

        byte[] temp = null;

        if (operands[0].contains("R") || operands[0].contains("r")) { // if first operand contains R, else
            // it's in error
            logger.debug("operand[0] contained a register");
            if (operands[1].contains("[")) { // if 2nd operand contains an [,
                // check if it also has an R
                logger.debug("operand[1] contained a bracket, means we have a memory address");
                if (operands[1].contains("R") || operands[1].contains("r")) { // if it is an R then it's
                    // opcode D
                    logger.debug("operands[1] contained an R so it's opcode D: " + operands[1]);
                    temp = this.getInstructions();
                    byte byte1 = extractNumber("0xD0");
                    logger.debug("hexByte = " + byte1);

                    temp[location] = byte1; // this is
                    // the D
                    // instruction
                    String byte2 = operands[0].substring(1) + operands[1].substring(2, 3);// need to get
                    // number
                    // after 'R' and after
                    // '[R', put them
                    // together that gives
                    // us two register
                    // indices
                    try {
                    	byte hexByte = (byte) Integer.parseInt(byte2, 16);
                    	logger.debug("hexByte = " + hexByte);

                    	temp[++location] = hexByte;
                    	this.setInstructions(temp);
                    } catch (NumberFormatException nfe) {
                    	this.setError(true);
                    	this.getErrors().add("Line " + this.getLineNumber() + ": Not an immediate. Expected: number,string");
                    }

                } else { // else if its the immediate value load
                	try {
                		logger.debug("else we have an direct load, opcode 1");
                		temp = this.getInstructions();
                		byte hexByte = (byte) Integer.parseInt("1" + operands[0].substring(1), 16);
                		logger.debug("hexByte = " + hexByte);

                		temp[location] = hexByte;
                		logger.debug("operands[1] = " + operands[1]);

                		hexByte = extractNumber(operands[1].substring(operands[1].indexOf("[") + 1, operands[1].indexOf("]"))); // need

                		logger.debug("hexByte = " + hexByte);
                		temp[++location] = hexByte;
                		this.setInstructions(temp);
                	} catch (NumberFormatException nfe) {
                		this.setError(true);
                    	this.getErrors().add("Line " + this.getLineNumber() + ": Not an immediate. Expected: number,string");
                    }
                }

            } else {
            	
                logger.debug("found the immediate value load instruction");
                temp = this.getInstructions();
                byte hexByte = (byte) Integer.parseInt("2" + operands[0].substring(1), 16);
                logger.debug("hexByte = " + hexByte);
                temp[location] = hexByte;

                if (operands[1].matches(this.hexRegEx) || operands[1].matches(this.decRegEx)) {
                    hexByte = extractNumber(operands[1]);

                    logger.debug("hexByte1 = " + hexByte);
                    temp[++location] = hexByte;
                    this.setInstructions(temp);
                } else {
                    //error invalid argument
                    this.setError(true);
                    this.getErrors().add(
                            "Line " + this.getLineNumber() + "Invalid Argument: " + operands[1] + ", expected a valid number.");
                }
            }
        } else {
            // error
            // invalid argument
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Invalid Argument: " + operands[0] + ", expected a register id.");
        }
    }

    private void writeStore(String[] ops, int location) {
        logger.debug("We have a store opcode!");
        byte[] temp = this.getInstructions();

        if (ops[0].contains("R") || ops[0].contains("r")) {// check to make sure first operand has an R
            logger.debug("first argument contains a register id");

            if (ops[1].contains("[") && ops[1].contains("]")) // second
            // operand
            // needs to have
            // bracket
            // enclosures...
            {
                try {
                    if (ops[1].contains("R") || ops[1].contains("r")) {
                        // opcode is going to be E
                        logger.debug("Indirect Store: operands[1] contained an R so it's opcode E");
                        byte byte1 = extractNumber("0xE0");
                        temp[location++] = byte1;

                        // going to write out the second byte which contains the
                        // second register
                        String hex = ops[0].substring(1) + ops[1].substring(2, 3);
                        logger.debug("The hex string looks like: " + hex);
                        if (hex.matches(hexRegEx2)) {
                        	byte byte2 = (byte) Integer.parseInt(hex, 16);
                            temp[location] = byte2;	
                        } else {
                        	this.setError(true);
                        	this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error. Expected: number, string");
                        }

                    } else {
                        // opcode is going to be 3

                        logger.debug("Direct Store: operands[1] must contain a memory location, so opcode 3");
                        String byte1 = "3" + ops[0].substring(1);
                        logger.debug("The first byte looks like: " + byte1);
                        if (byte1.matches(hexRegEx2)) {
                        	byte bit1 = (byte) Integer.parseInt(byte1, 16);
                            temp[location++] = bit1;

                            // going to write out the second byte which is a hex
                            // value
                            String byte2 = ops[1].substring(
                                    ops[1].indexOf("[") + 1, ops[1].indexOf("]")); // get
                            // everything
                            // in between
                            // the brackets
                            logger.debug("The second byte looks like: " + byte2);
                            byte bit2 = extractNumber(byte2);
                            temp[location] = bit2;
                        } else {
                        	this.setError(true);
                        	this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error. Expected register ID");
                        }

                    }
                } catch (Exception e) {
                    // got an error somehow
                    // error
                    // invalid argument
                    this.setError(true);
                    this.getErrors().add(
                            "Line " + this.getLineNumber() + ": General Syntax Error.");
                }
            } else if (this.getOpLabel()) {
                // opcode is going to be 3
                // a label was found so we subbed in the direct memory location
                logger.debug("Direct Store: operands[1] must contain a memory location, so opcode 3");
                String byte1 = "3" + ops[0].substring(1);
                logger.debug("The first byte looks like: " + byte1);
                if (byte1.matches(hexRegEx2)) {
                	byte bit1 = (byte) Integer.parseInt(byte1, 16);
                    temp[location++] = bit1;

                    // going to write out the second byte which is a hex value
                    String byte2 = ops[1]; // get everything inbetween
                    // the brackets
                    logger.debug("The second byte looks like: " + byte2);
                    byte bit2 = extractNumber(byte2);
                    temp[location] = bit2;
                    this.setOpLabel(false);	
                } else {
                	this.setError(true);
                	this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error. Expected number, string");
                }
                
            } else {
                // since second operand doesn't have brackets then we need to
                // add an error
                this.setError(true);
                this.getErrors().add(
                        "Line " + this.getLineNumber() + ": '[]' Not Found For 2nd Argument. '[]' Required.");
            }
        } else {
            // invalid argument
            this.setError(true);
            this.getErrors().add(
                     "Line " + this.getLineNumber() + ": Invalid Argument: " + ops[0] + ", expected a register id.");

        }

    }

    private void writeJmpLE(String[] operands, int location) {
        logger.debug("We have a Jmp opcode");
        logger.debug("First operand is: " + operands[0].toString());
        byte[] temp = this.getInstructions();
        if (operands[0].substring(0, 1).matches("R|r")) {// check to make sure
            // first operand has
            // an R
            // if first operand has an R, it will either be JmpEQ or JmpLE
            if (operands[0].substring(1, 2).matches(hexRegEx1)) {
                if (operands[0].contains("<=")) {
                    // JmpLE, opcode F
                    // format of FRXY
                    logger.debug("Our instruction is a JmpLE");
                    // The second character of the first operand should be the
                    // register (i.e. RF<=R0, R2<=R0, etc)
                    String byte1 = "F" + operands[0].charAt(1);
                    logger.debug("The first byte looks like: " + byte1);
                    byte bit1 = (byte) Integer.parseInt(byte1, 16);
                    logger.debug("bit1 assigned as: " + bit1);
                    temp[location++] = bit1;
                    logger.debug("bit1 assigned to temp array");

                    // need second byte, will almost always be a label
                    // translating
                    // to a mem location, but should be preemptively translated
                    logger.debug("The second operand is: " + operands[1]);
                    String byte2 = operands[1];
                    logger.debug("The second byte looks like: " + byte2);
                    byte bit2 = 0;
                    if (byte2.contains("[") && byte2.contains("]")) {
                        if (byte2.contains("0x")) {
                            bit2 = extractNumber(byte2.substring(1, byte2.length() - 1));
                        } else {
                            // decimal number
                        	try {
                        		bit2 = (byte) Integer.parseInt(byte2.substring(1,
                        				byte2.length() - 1));
                        	} catch (NumberFormatException nfe) {
                        		this.setError(true);
                        		this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error. Expected: number, string");
                        	}
                        }
                    } else if (byte2.contains("0x")) {
                        bit2 = extractNumber(byte2);
                    } else {
                    	try {
                    		bit2 = (byte) Integer.parseInt(byte2);
                    	} catch (NumberFormatException nfe) {
                    		this.setError(true);
                    		this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error. Expected: number, string");
                    	}
                    	
                    }
                    logger.debug("numbers extracted from second byte: " + bit2);
                    temp[location] = bit2;
                } else {
                    // error
                    this.setError(true);
                    this.getErrors().add(
                            "Line " + this.getLineNumber() + ": Syntax error. Expected: '<='");
                }
            } else {
                // error
                this.setError(true);
                this.getErrors().add(
                        "Line " + this.getLineNumber() + ": Syntax error. Expected: register");
            }

        } else {
            // error
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Syntax error. Expected: register");
        }

    }

    private void writeJmpEQ(String[] operands, int location) {
        logger.debug("We have a Jmp opcode");
        operands[0] = operands[0].replace(" +", ""); // strip spaces
        logger.debug("First operand is: " + operands[0].toString());
        byte[] temp = this.getInstructions();
        if (operands[0].substring(0, 1).matches("R|r")) {// check to make sure
            // first operand has
            // an R
            // if first operand has an R, it will either be JmpEQ or JmpLE

            if (operands[0].contains("=")) {
                // JmpEQ, opcode B
                logger.debug("Our instruction is a JmpEQ");
                // The second character of the first operand should be the
                // register (i.e. RF<=R0, R2<=R0, etc)
                if (operands[0].substring(1, 2).matches(hexRegEx1)) {

                    String byte1 = "B" + operands[0].charAt(1);
                    logger.debug("The first byte looks like: " + byte1);
                    byte bit1 = (byte) Integer.parseInt(byte1, 16);
                    temp[location++] = bit1;

                    // need second byte, will almost always be a label
                    // translating
                    // to a mem location, but should be preemptively translated
                    String byte2 = operands[1];
                    logger.debug("The second byte looks like: " + byte2);
                    byte bit2 = 0;
                    if (byte2.contains("[") && byte2.contains("]")) {
                        if (byte2.contains("0x")) {
                            bit2 = extractNumber(byte2.substring(1, byte2.length() - 1));
                        } else {
                            // decimal number
                        	try {
                        		bit2 = (byte) Integer.parseInt(byte2.substring(1,
                        				byte2.length() - 1));
                        	} catch (NumberFormatException nfe) {
                        		this.setError(true);
                        		this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error. Expected: number, string");
                        	}
                        }
                    } else if (byte2.contains("0x")) {
                        bit2 = extractNumber(byte2);
                    } else {
                    	try {
                    		bit2 = (byte) Integer.parseInt(byte2);
                    	} catch(NumberFormatException nfe) {
                    		this.setError(true);
                    		this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error. Expected: number, string");
                    	}
                    }
                    logger.debug("Second bit looks like: " + bit2);

                    temp[location] = bit2;
                } else {
                    // error
                    this.setError(true);
                    this.getErrors().add(
                            "Line " + this.getLineNumber() + ": Syntax error. Expected: register");
                }
            } else {
                // error
                this.setError(true);
                this.getErrors().add(
                        "Line " + this.getLineNumber() + ": Syntax error. Expected: '='");
            }

        } else {
            // error
            this.setError(true);
            this.getErrors().add(
                    "Line " + this.getLineNumber() + ": Syntax error. Expected: register");
        }

    }

    /**
     *
     * @param operands
     * @param location
     */
    public void writeJmp(String[] operands, int location) {
        logger.debug("We have a Jmp opcode");
        operands[0] = operands[0].replace(" +", ""); // strip spaces
        logger.debug("First operand is: " + operands[0].toString());
        byte[] temp = this.getInstructions();

        // unconditional Jmp, only gives one operand, a memory location
        // opcode B0
        logger.debug("Our instruction is an unconditional jump");
        String byte1 = "B0";
        logger.debug("The first byte looks like: " + byte1);
        try {
        	byte bit1 = (byte) Integer.parseInt(byte1, 16);
        	temp[location++] = bit1;
        } catch(NumberFormatException nfe) {
    		this.setError(true);
    		this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error. Expected: number, string");
    	}
        // now for the second byte, the memory location (or label)
        String byte2 = operands[0];
        logger.debug("The second byte looks like: " + byte2);
        byte bit2 = 0;
        if (byte2.contains("[") && byte2.contains("]")) {
            if (byte2.contains("0x")) {
                bit2 = extractNumber(byte2.substring(1, byte2.length() - 1));
            } else {
                // decimal number
            	try {
            		bit2 = (byte) Integer.parseInt(byte2.substring(1, byte2.length() - 1));
            	} catch(NumberFormatException nfe) {
            		this.setError(true);
            		this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error. Expected: number, string");
            	}
            }
        } else if (byte2.contains("0x")) {
            bit2 = extractNumber(byte2);
        } else {
        	try {
                // Bartis+Vance:
                // This was the culprit for the JMP instruction
                // We think there is something further down in the processing that
                // parses the instruction array into hex for display, but everything 
                // internal is a decimal.  The original line of code was:
                // bit2 = (byte) Integer.parseInt(byte2, 16);
                bit2 = (byte) Integer.parseInt(byte2);
        	} catch(NumberFormatException nfe) {
        		this.setError(true);
        		this.getErrors().add("Line " + this.getLineNumber() + ": Syntax error. Expected: number, string");
        	}
        }
        temp[location] = bit2;

    }

    private byte extractNumber(String string) {
        // |(\\$[0-9A-F]{2})|(0[A-F0-9]h)|(
        // [0-9
        // A-F]{2}h)";

        // if it matches then we return and exit out of this method
        // otherwise returns null;
        if (string.matches(hexRegEx)) {
            logger.debug("Matched hexRegEx");
            return (byte) Integer.parseInt(string.substring(2), 16);

        } else if (string.matches(decRegEx)) {
            logger.debug("Matched decRegEx");
            return (byte) Integer.parseInt(string, 10);

        }
        return -1;
    }

    /**
     *
     * @return
     */
    public int getLocation_counter() {
        return location_counter;
    }

    /**
     *
     * @param location_counter
     */
    public void setLocation_counter(int location_counter) {
        this.location_counter = location_counter;
    }

    /**
     * @param foundHalt
     *            the foundHalt to set
     */
    // Team Alpha:  missing method here??
    
    /**
     * @param error
     *            the error to set
     */
    public void setError(boolean error) {
        this.error = error;
    }

    /**
     * @return the error
     */
    public boolean getError() {
        return error;
    }

    /**
     * @param errors
     *            the errors to set
     */
    public void setErrors(ArrayList<String> errors) {
        Errors = errors;
    }

    /**
     * @return the errors
     */
    public ArrayList<String> getErrors() {
        return Errors;
    }

    /**
     * @param opLabel
     *            the opLabel to set
     */
    public void setOpLabel(boolean opLabel) {
        this.opLabel = opLabel;
    }

    /**
     * @return the opLabel
     */
    public boolean getOpLabel() {
        return opLabel;
    }

    /**
     * @param lineNumber
     *            the lineNumber to set
     */
    public void setLineNumber(int lineNumber) {
        this.lineNumber = lineNumber;
    }

    /**
     * @return the lineNumber
     */
    public int getLineNumber() {
        return lineNumber;
    }

    /**
     *
     * @return
     */
    public boolean getFoundSymbol() {
        return foundSymbol;
    }

    /**
     *
     * @param foundSymbol
     */
    public void setFoundSymbol(boolean foundSymbol) {
        this.foundSymbol = foundSymbol;
    }
}
